package domotica.house.manager;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jws.WebService;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import domotica.house.automation.ActuatorSensor;
import domotica.house.automation.Parameter;

/**
 * Questa classe rappresenta il cuore dell'applicazione server e il punto di partenza per la definizione dei componenti collegati 
 * sulla rete e degli utenti, attraverso i metodi <code>initActuatorsSensors</code> e <code>addActuatorSensor</code>.
 * 
 * Tutti i metodi di questa classe per la gestione dei componenti risultano protected in quanto la vera comunicazione utente-server avviene
 * attraverso un'istanza della classe HouseOwner, rendendo quindi il WS stateful.
 * 
 * Fondamentale e' quindi il metodo login che a valle della verifica dell'identita' dell'utente permette di ottenere 
 * un riferimento ad un W3CEndpointReference e quindi ad un'istanza di HouseOwner.
 */

@WebService
public abstract class HouseManager {
	
	private Map<String,ActuatorSensor> actuatorsSensorsList;
	private Map<String,HouseOwner> userList;
	
	protected abstract void initActuatorsSensors();
	
	protected abstract void initUsers();
	
	public HouseManager(){
		this.actuatorsSensorsList=new HashMap<String,ActuatorSensor>();
		this.userList=new HashMap<String,HouseOwner>();
	}
	
	/**
	 * Permette di effettuare il login inserendo username e password.
	 * @throws RuntimeException Se password o username errati
	 */
	public synchronized W3CEndpointReference login(String user, String password) {
		
		if (this.userList.get(user)!=null)
			if (this.userList.get(user).getPassword().equals(password))
				return HouseOwner.manager.export(userList.get(user));
			
		throw new RuntimeException("Unvalid username or password!");
	}
	
	/**
	 * Aggiunge un ActuatorSensor alla lista di quelli disponibili durante
	 * la fase di inizializzazione del server.
	 */
	protected void addActuatorSensor(ActuatorSensor actSen){
		this.actuatorsSensorsList.put(actSen.getName(), actSen);
	}
	
	/**
	 * Aggiunge un utente alla lista di quelli disponibili durante
	 * la fase di inizializzazione del server.
	 */
	protected void addUser(String username, String password){
		
		this.userList.put(username, new HouseOwner(username, password, this));
	}
	
	/**
	 * Restituisce i nomi di tutte le variabili monitorate dai componenti collegati
	 */
	protected List<String> getEnvironmentVariablesNames(){
		
		List<String> environmentVariablesNames = new ArrayList<String>();
		
		for (ActuatorSensor actuatorSensor : this.actuatorsSensorsList.values()){
			environmentVariablesNames.add(actuatorSensor.getMeasureName());
		}
		return environmentVariablesNames;	
	}
	
	/**
	 * Restituisce il valore di tutte le variabili monitorate dai componenti collegati
	 */
	protected List<Double> getEnvironmentVariables(){
		
			List<Double> environmentVariables = new ArrayList<Double>();
			
			for (ActuatorSensor actuatorSensor : this.actuatorsSensorsList.values()){
				environmentVariables.add(actuatorSensor.getMeasure());
			}
			return environmentVariables;		
	}
		
	protected boolean isActuatorSensorOn(String actuatorSensorName){
		return this.actuatorsSensorsList.get(actuatorSensorName).isOn();
	}
		
	/**
	 * Restituisce i nomi di tutti gli ActuatorSensor
	 */
	protected List<String> getActuatorsSensorsNameList(){
		return new ArrayList<String>(this.actuatorsSensorsList.keySet());
	}

	/**
	 * Restituisce la lista di parametri necessari ad un ActuatorSensor per la definizione di un task
	 */
	protected List<Parameter> getActuatorSensorTaskDesiredParameterList(String actuatorSensorName) {
		return this.actuatorsSensorsList.get(actuatorSensorName).getTaskDesiredParameterList();
	}
	
	/**
	 * Definisce un nuovo task per il componente secondo i parametri passati
	 */
	protected synchronized void addActuatorSensorTask(String actuatorSensorName, List<String> parameterList){
		this.actuatorsSensorsList.get(actuatorSensorName).addTask(parameterList);
	}
	
	/**
	 * Blocca il task del componente desiderato 
	 */
	protected synchronized void stopTask(String actuatorSensorName){
		this.actuatorsSensorsList.get(actuatorSensorName).stopTask();
	}
}
